﻿using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Data.SQLite;
using System.Linq;
using System.Data.Linq.Mapping;
using System.Data.Linq;
using System.Data;
using System.Data.Objects;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using BazingaProtokol;
using System.Collections.Generic;
using System.Collections;

namespace Posluzitelj
{
    /// <summary>
    /// Staticna klasa koja predstavlja posluzitelj.
    /// </summary>
    public static class Posluzitelj
    {
        #region Varijable razreda (dijeljene izmedju rukovatelja klijentima)

        private static bool prekidaRad;
        /// <summary>
        /// Svojstvo koje signalizira da posluzitelj staje s radom.
        /// </summary>
        public static bool PrekidaRad { get { return prekidaRad; } }

        /// <summary>
        /// Stanje posluzitelja koje sluzi za omogucavanje glasovanja.
        /// </summary>
        public static bool DozvoljenoGlasovanje { get; set; }

        /// <summary>
        /// Svojstvo koje pamti trenutno aktivne birace.
        /// </summary>
        internal static List<string> PrijavljeniBiraci { get; set; }

        internal static object locker = new object();
        private static int BrojKlijenta = 0;
        private static TcpListener tcpOsluskivac;

        #endregion

        /// <summary>
        /// Ulazna tocka programa posluzitelja.
        /// </summary>
        public static void Main()
        {
            try
            {
                // Stvara se tcpOsluskivac koji osluskuje na portu 49152
                tcpOsluskivac = new TcpListener(IPAddress.Parse("127.0.0.1"), 49152);

                Console.WriteLine("Pocinje osluskivanje klijentskih zahtjeva...");

                // tcpOsluskivac pocinje s radom.
                prekidaRad = false;
                DozvoljenoGlasovanje = false;
                PrijavljeniBiraci = new List<string>();
                tcpOsluskivac.Start();

                // Asinkrono se osluskuje. RukujKonekcijom je callback metoda.
                tcpOsluskivac.BeginAcceptTcpClient(RukujKonekcijom, null);

                // Posluzitelj je aktivan dok korisnik ne pritisne enter.
                Console.WriteLine("Posluzitelj ocekuje konekciju. " +
                    "Pritisnuti enter za prestanak rada.");
                Console.ReadLine();
            }
            finally
            {
                //Gasenje tcpOsluskivaca. 
                Console.WriteLine("Posluzitelj staje s radom...");
                prekidaRad = true;
                if (tcpOsluskivac != null) tcpOsluskivac.Stop();
            }

            // Cekaj na potvrdu kraja. 
            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("Posluzitelj stao s radom. Pritisnuti enter.");
            Console.ReadLine();
        }

        /// <summary>
        /// Callback metoda koja se poziva nakon uspostavljanja veze s klijentom.
        /// </summary>
        /// <param name="result">Rezultat asinkronog poziva</param>
        private static void RukujKonekcijom(IAsyncResult result)
        {
            TcpClient tcpKlijent = null;

            // Zavrsavanje asinktronog poziva.
            try
            {
                // Dohvacanje tcpKlijenta
                tcpKlijent = tcpOsluskivac.EndAcceptTcpClient(result);
            }
            catch (ObjectDisposedException)
            {
                // Gasenje servera.
                return;
            }

            Console.WriteLine("Prihvaćena nova konekcija.");

            // Asinkrono osluskivanje za slijedeci zahtjev
            tcpOsluskivac.BeginAcceptTcpClient(RukujKonekcijom, null);

            if (tcpKlijent != null)
            {
                // Odredjivanje identiteta spojenog klijenta
                Interlocked.Increment(ref BrojKlijenta);
                string imeKlijenta = "Klijent " + BrojKlijenta.ToString();

                Console.WriteLine("Stvara se rukovatelj za klijenta ({0})."
                    , imeKlijenta);

                // Stvara se rukovatelj za klijenta.
                new RukovateljKlijentom(tcpKlijent, imeKlijenta);
            }
        }
    }

    /// <summary>
    /// Klasa koja enkapsulira logiku za interakciju s klijentom.
    /// </summary>
    public class RukovateljKlijentom
    {
        #region Privatne varijable instance

        private TcpClient klijent;
        private NetworkStream mrezniTok;
        private BinaryFormatter binFormater;
        private string ID;

        #endregion

        #region Konstruktori klase

        /// <summary>
        /// Konstruktor rukovatelja - pridruzuje rukovatelju identifikator i tcp klijenta.
        /// </summary>
        /// <code lang="cs">
        /// // Svaki rukovatelj klijentom ima svoj tcpKlijent (apstrahira socket),
        /// // svoj mrezni tok prema klijentu, te binarni formater za serijalizaciju
        /// // objekata na tok.
        /// this.klijent = klijent;
        /// this.mrezniTok = klijent.GetStream();
        /// this.binFormater = new BinaryFormatter();
        /// this.ID = ID;
        ///
        /// // Stvara se pozadinska dretva za komunikaciju s klijentom.
        /// Thread thread = new Thread(ObradiKlijenta);
        /// thread.IsBackground = true;
        /// thread.Start();
        /// </code>
        /// <param name="klijent">TCP klijent koji se pridruzuje rukovatelju</param>
        /// <param name="ID">Identifikator rukovatelja</param>
        /// 
        internal RukovateljKlijentom(TcpClient klijent, string ID)
        {
            // Svaki rukovatelj klijentom ima svoj tcpKlijent (apstrahira socket),
            // svoj mrezni tok prema klijentu, te binarni formater za serijalizaciju
            // objekata na tok.
            this.klijent = klijent;
            this.mrezniTok = klijent.GetStream();
            this.binFormater = new BinaryFormatter();
            this.ID = ID;

            // Stvara se pozadinska dretva za komunikaciju s klijentom.
            Thread thread = new Thread(ObradiKlijenta);
            thread.IsBackground = true;
            thread.Start();
        }

        #endregion

        #region Zajednicke metode za obje vrste klijenata

        /// <summary>
        /// Metoda koja odradjuje ukupnu komunikaciju s klijentom.
        /// </summary>
        private void ObradiKlijenta()
        {

            try
            {
                Poruka pitanje = (JednostavnaPoruka)binFormater.Deserialize(mrezniTok);
                Console.WriteLine("Primljena poruka.");
                Poruka odgovor = null;

                // Poruke se obradjuju dok klijent ne zatrazi raskid veze.
                while (pitanje.TipPoruke != Tip.PitanjeKraj)
                {
                    odgovor = ObradiPoruku(pitanje);
                    Console.WriteLine("Obradjena poruka.");
                    binFormater.Serialize(mrezniTok, odgovor);
                    Console.WriteLine("Poslan odgovor.");
                    pitanje = (Poruka)binFormater.Deserialize(mrezniTok);
                    Console.WriteLine("Primljena poruka.");
                }

                // Odgovor na zahtjev za raskid.
                odgovor.TipPoruke = Tip.OdgovorKraj;
                binFormater.Serialize(mrezniTok, odgovor);
            }
            catch (Exception)
            {
                Console.WriteLine("Klijent se odspojio.");
            }
        }

        /// <summary>
        /// Metoda koja ovisno o vrsti dolazne poruke odabire metodu za obradu.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka</param>
        /// <returns>Odlazna poruka</returns>
        private Poruka ObradiPoruku(Poruka pitanje)
        {
            Poruka odgovor = null;

            switch (pitanje.TipPoruke)
            {
                case Tip.PitanjeLozinka:
                    odgovor = ObradiLozinkuAdmina((JednostavnaPoruka)pitanje);
                    break;
                case Tip.PitanjeIzborneJedinice:
                    odgovor = ObradiIzborneJedinice(pitanje);
                    break;
                case Tip.PitanjeStranke:
                    odgovor = ObradiDohvatStranki(pitanje);
                    break;
                case Tip.PitanjeDohvatiListe:
                    odgovor = ObradiDohvatLista((JednostavnaPoruka)pitanje);
                    break;
                case Tip.PitanjeStvoriListu:
                    lock (Posluzitelj.locker)
                    {
                        if (Posluzitelj.DozvoljenoGlasovanje)
                        {
                            odgovor = new JednostavnaPoruka(Tip.Pogreska, new object[] { "Glasovanje u tijeku." });
                        }
                        else
                        {
                            odgovor = ObradiStvaranjeListe((JednostavnaPoruka)pitanje);
                        }
                    }
                    break;
                case Tip.PitanjeIzmijeniListu:
                    lock (Posluzitelj.locker)
                    {
                        if (Posluzitelj.DozvoljenoGlasovanje)
                        {
                            odgovor = new JednostavnaPoruka(Tip.Pogreska, new object[] { "Glasovanje u tijeku." });
                        }
                        else
                        {
                            odgovor = ObradiIzmjenuListe((JednostavnaPoruka)pitanje);
                        }
                    }
                    break;
                case Tip.PitanjeObrisiListu:
                    lock (Posluzitelj.locker)
                    {
                        if (Posluzitelj.DozvoljenoGlasovanje)
                        {
                            odgovor = new JednostavnaPoruka(Tip.Pogreska, new object[] { "Glasovanje u tijeku." });
                        }
                        else
                        {
                            odgovor = ObradiBrisanjeListe((JednostavnaPoruka)pitanje);
                        }
                    }
                    break;
                case Tip.PitanjeOmoguciGlasovanje:
                    lock (Posluzitelj.locker)
                    {
                        if (Posluzitelj.DozvoljenoGlasovanje)
                        {
                            odgovor = new JednostavnaPoruka(Tip.Pogreska, new object[] { "Glasovanje je vec u tijeku." });
                        }
                        else
                        {
                            odgovor = ObradiDozvoluGlasovanja(pitanje);
                        }
                    }
                    break;
                case Tip.PitanjeOnemoguciGlasovanje:
                    lock (Posluzitelj.locker)
                    {
                        if (!Posluzitelj.DozvoljenoGlasovanje)
                        {
                            odgovor = new JednostavnaPoruka(Tip.Pogreska, new object[] { "Glasovanje je vec onemoguceno." });
                        }
                        else
                        {
                            odgovor = ObradiZabranuGlasovanja(pitanje);
                        }
                    }
                    break;
                case Tip.PitanjeRezultat:
                    lock (Posluzitelj.locker)
                    {
                        if (Posluzitelj.DozvoljenoGlasovanje)
                        {
                            odgovor = new JednostavnaPoruka(Tip.Pogreska, new object[] { "Glasovanje u tijeku." });
                        }
                        else
                        {
                            odgovor = ObradiDohvatRezultata((JednostavnaPoruka)pitanje);
                        }
                    }
                    break;
                case Tip.PitanjeLozinkaBirac:
                    lock (Posluzitelj.locker)
                    {
                        if (!Posluzitelj.DozvoljenoGlasovanje)
                        {
                            odgovor = new JednostavnaPoruka(Tip.Pogreska, new object[] { "Glasovanje nije u tijeku." });
                        }
                        else
                        {
                            odgovor = ObradiLozinkuBiraca((JednostavnaPoruka)pitanje);
                        }
                    }
                    break;
                case Tip.PitanjeListeBirac:
                    odgovor = ObradiListeBiraca((JednostavnaPoruka)pitanje);
                    break;
                case Tip.PitanjeOdabirBirac:
                    lock (Posluzitelj.locker)
                    {
                        if (!Posluzitelj.DozvoljenoGlasovanje)
                        {
                            odgovor = new JednostavnaPoruka(Tip.Pogreska, new object[] { "Glasovanje nije u tijeku." });
                        }
                        else
                        {
                            odgovor = ObradiOdabirBiraca((JednostavnaPoruka)pitanje);
                        }
                    }
                    break;
                default:
                    odgovor.TipPoruke = Tip.Pogreska;
                    break;
            }

            return odgovor;
        }

        /// <summary>
        /// Dohvat podataka o strankama
        /// </summary>
        /// <param name="pitanje">Dolazna poruka</param>
        /// <returns>Odlazna poruka</returns>
        private JednostavnaPoruka ObradiDohvatStranki(Poruka pitanje)
        {
            JednostavnaPoruka odgovor = new JednostavnaPoruka();
            odgovor.TipPoruke = Tip.OdgovorStranke;


            using (BazingaEntities kontekst = new BazingaEntities())
            {
                IQueryable<stranka> upitZaStranke =
                     from s in kontekst.stranka
                     select s;

                odgovor.Podaci = new object[upitZaStranke.Count()];

                int i = 0;
                foreach (stranka s in upitZaStranke)
                {
                    odgovor.Podaci[i++] = new object[]
                    { 
                        (int)s.IDstranka,
                        s.nazivstranka,
                        s.kratica
                    };
                }

                return odgovor;
            }
        }

        /// <summary>
        /// Dohvat izbornih lista u odredjenoj izbornoj jedinici.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka s brojem izborne jedinice</param>
        /// <returns>Odlazna porka s izbornim listama</returns>
        private PorukaListe ObradiDohvatLista(JednostavnaPoruka pitanje)
        {
            PorukaListe odgovor = new PorukaListe();
            odgovor.TipPoruke = Tip.OdgovorDohvatiListe;
            int odabranaJedinica = (int)pitanje.Podaci[0];

            using (BazingaEntities kontekst = new BazingaEntities())
            {
                var odabranaGrupaPrijava =
                     from iL in kontekst.izbornaLista
                     from pS in kontekst.prijavaStranke
                     from s in kontekst.stranka
                     where iL.IDjedinica == odabranaJedinica
                      && iL.IDjedinica == pS.IDjedinica
                      && iL.rbr == pS.rbr
                      && pS.IDstranka == s.IDstranka
                     group s by new { RedniBroj = iL.rbr, NazivListe = iL.nazivlista } into grupaPrijava
                     orderby grupaPrijava.Key.RedniBroj
                     select grupaPrijava;

                odgovor.PopisIzbornihLista = new List<IzbornaLista>();

                int i = 0;
                foreach (var prijave in odabranaGrupaPrijava)
                {
                    List<int> ListaIDStranaka = new List<int>();

                    foreach (var stranka in prijave)
                    {
                        ListaIDStranaka.Add((int)stranka.IDstranka);
                    }

                    odgovor.PopisIzbornihLista.Add(
                       new IzbornaLista()
                       {
                           RedniBroj = (int)prijave.Key.RedniBroj,
                           Naziv = prijave.Key.NazivListe,
                           PopisIDStranaka = ListaIDStranaka
                       });

                    i++;
                }
            }
            return odgovor;
        }

        #endregion

        #region Metode za obradu administratorskih poruka

        /// <summary>
        /// Vraca klijentu lozinku za odredjeno korisnicko ime.
        /// </summary>
        /// <example>
        /// Primjer LINQ upita
        /// <code lang="cs">IQueryablestring> upitZaLozinku = from a in kontekst.administrator
        ///                                        where a.korime == korisnickoIme
        ///                                        select a.lozinka;
        /// </code>
        /// </example>
        /// <param name="pitanje">Dolazna poruka s korisnickim imenom.</param>
        /// <returns>Odlazna poruka s lozinkom</returns>
        private JednostavnaPoruka ObradiLozinkuAdmina(JednostavnaPoruka pitanje)
        {
            string korisnickoIme = (string)pitanje.Podaci[0];
            using (BazingaEntities kontekst = new BazingaEntities())
            {
                IQueryable<string> upitZaLozinku = from a in kontekst.administrator
                                                   where a.korime == korisnickoIme
                                                   select a.lozinka;

                if (upitZaLozinku.Count() == 1)
                {
                    return new JednostavnaPoruka()
                    {
                        TipPoruke = Tip.OdgovorLozinka,
                        Podaci = new object[] { upitZaLozinku.Single() }
                    };
                }
                else
                {
                    return new JednostavnaPoruka()
                    {
                        TipPoruke = Tip.Pogreska,
                        Podaci = new object[] { "Ne postoji korisnicko ime." }
                    };
                }
            }
        }

        /// <summary>
        /// Metoda koja vraca poruku s podacima o izbornim jedinicama.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka</param>
        /// <returns>Odlazna poruka s podacima</returns>
        private JednostavnaPoruka ObradiIzborneJedinice(Poruka pitanje)
        {
            JednostavnaPoruka odgovor = new JednostavnaPoruka();
            odgovor.TipPoruke = Tip.OdgovorIzborneJedinice;


            using (BazingaEntities kontekst = new BazingaEntities())
            {
                IQueryable<izbornaJedinica> upitZaJedinice =
                     from iJed in kontekst.izbornaJedinica
                     select iJed;

                odgovor.Podaci = new object[upitZaJedinice.Count()];

                int i = 0;
                foreach (izbornaJedinica iJed in upitZaJedinice)
                {
                    odgovor.Podaci[i++] = new object[]
                    { 
                        (int)iJed.IDjedinica,
                        iJed.nazivjedinica,
                    };
                }

                return odgovor;
            }
        }

        /// <summary>
        /// Metoda koja obavlja operaciju stvaranja izborne liste
        /// </summary>
        /// <param name="pitanje">Dolazna poruka s podacima o novoj izbornoj listi</param>
        /// <returns>Odgovor o stvaranju liste</returns>
        /// <example>Primjer promjena entiteta pomocu LINQ-a
        /// <code lang="cs">
        /// foreach (var idStranke in predanaIzbornaLista.PopisIDStranaka)
        ///     {
        ///         prijavaStranke tempPrijava = new prijavaStranke();
        ///         tempPrijava.IDjedinica = novaIzbornaLista.IDjedinica;
        ///         tempPrijava.IDstranka = idStranke;
        ///         tempPrijava.rbr = novaIzbornaLista.rbr;
        ///         kontekst.prijavaStranke.AddObject(tempPrijava);
        ///     }
        /// </code>
        /// </example>
          
        private JednostavnaPoruka ObradiStvaranjeListe(JednostavnaPoruka pitanje)
        {
            using (BazingaEntities kontekst = new BazingaEntities())
            {
                IzbornaLista predanaIzbornaLista = (IzbornaLista)pitanje.Podaci[1];
                izbornaLista novaIzbornaLista = new izbornaLista();
                int odabranaIDJedinica = (int)pitanje.Podaci[0];
                novaIzbornaLista.IDjedinica = odabranaIDJedinica;
                novaIzbornaLista.nazivlista = predanaIzbornaLista.Naziv;
                if (kontekst.izbornaLista.Where(x => x.IDjedinica == odabranaIDJedinica).Count() == 0)
                {
                    novaIzbornaLista.rbr = 1;
                }
                else
                {
                    novaIzbornaLista.rbr = (from iL in kontekst.izbornaLista
                                            where iL.IDjedinica == novaIzbornaLista.IDjedinica
                                            select iL.rbr).Max() + 1;
                }
                

                izbornaJedinica iJ = kontekst.izbornaJedinica.Single(ij => ij.IDjedinica == novaIzbornaLista.IDjedinica);
                iJ.izbornaLista.Add(novaIzbornaLista);

                foreach (var idStranke in predanaIzbornaLista.PopisIDStranaka)
                {
                    prijavaStranke tempPrijava = new prijavaStranke();
                    tempPrijava.IDjedinica = novaIzbornaLista.IDjedinica;
                    tempPrijava.IDstranka = idStranke;
                    tempPrijava.rbr = novaIzbornaLista.rbr;
                    kontekst.prijavaStranke.AddObject(tempPrijava);
                }

                kontekst.SaveChanges();

                return new JednostavnaPoruka() { TipPoruke = Tip.OdgovorStvoriListu };
            }
        }

        /// <summary>
        /// Metoda za brisanje izbornih listi.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka s identifikatorom liste za brisanje</param>
        /// <returns>Odlazna poruka o brisanju liste.</returns>
        private JednostavnaPoruka ObradiBrisanjeListe(JednostavnaPoruka pitanje)
        {
            using (BazingaEntities kontekst = new BazingaEntities())
            {
                int odabirJedinice = (int)pitanje.Podaci[0];
                int redniBrojListe = (int)pitanje.Podaci[1];

                var prijaveZaBrisati = from pS in kontekst.prijavaStranke
                                       where pS.IDjedinica == odabirJedinice
                                        && pS.rbr == redniBrojListe
                                       select pS;

                var prijaveZaSmanjitiRbr = from pS in kontekst.prijavaStranke
                                           where pS.IDjedinica == odabirJedinice
                                            && pS.rbr > redniBrojListe
                                           select pS;

                foreach (var prijavaStranke in prijaveZaBrisati)
                {
                    kontekst.prijavaStranke.DeleteObject(prijavaStranke);
                }

                foreach (var prijavaStranke in prijaveZaSmanjitiRbr)
                {
                    var tempPrijava = new prijavaStranke()
                        {
                            IDjedinica = prijavaStranke.IDjedinica,
                            IDstranka = prijavaStranke.IDstranka,
                            rbr = prijavaStranke.rbr - 1
                        };

                    kontekst.prijavaStranke.DeleteObject(prijavaStranke);
                    kontekst.prijavaStranke.AddObject(tempPrijava);
                }



                var listaZaBrisati = (from iL in kontekst.izbornaLista
                                     where iL.IDjedinica == odabirJedinice
                                       && iL.rbr == redniBrojListe
                                     select iL).Single();

                kontekst.izbornaLista.DeleteObject(listaZaBrisati);

                var listeZaSmanjitiRbr = from iL in kontekst.izbornaLista
                                          where iL.IDjedinica == odabirJedinice
                                            && iL.rbr > redniBrojListe
                                          select iL;
                foreach (var lista in listeZaSmanjitiRbr)
                {
                    var tempLista = new izbornaLista()
                    {
                        IDjedinica = lista.IDjedinica,
                        nazivlista = lista.nazivlista,
                        brojglasova = lista.brojglasova,
                        rbr = lista.rbr - 1
                    };

                    kontekst.izbornaLista.DeleteObject(lista);
                    kontekst.izbornaLista.AddObject(tempLista);
                }
                

                kontekst.SaveChanges();

                return new JednostavnaPoruka() { TipPoruke = Tip.OdgovorObrisiListu };
            }
        }

        /// <summary>
        /// Metoda za izmjene listi. Potrebno implementirati
        /// </summary>
        /// <param name="pitanje"></param>
        /// <returns></returns>
        private JednostavnaPoruka ObradiIzmjenuListe(JednostavnaPoruka pitanje)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Metoda mijenja stanje posluzitelja tako da se moze glasovati.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka o dozvoli glasovanja</param>
        /// <returns>Odlazna poruka koja potvrdjuje promjenu stanja.</returns>
        private JednostavnaPoruka ObradiDozvoluGlasovanja(Poruka pitanje)
        {
            JednostavnaPoruka odgovor = new JednostavnaPoruka();
            odgovor.TipPoruke = Tip.OdgovorOmoguciGlasovanje;

            lock (Posluzitelj.locker)
            {
                Posluzitelj.DozvoljenoGlasovanje = true;
            }

            return odgovor;
        }

        /// <summary>
        /// Metoda mijenja stanje posluzitelja tako da se ne moze glasovati.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka o zabrani glasovanja</param>
        /// <returns>Odlazna poruka koja potvrdjuje promjenu stanja.</returns>
        private JednostavnaPoruka ObradiZabranuGlasovanja(Poruka pitanje)
        {
            JednostavnaPoruka odgovor = new JednostavnaPoruka();
            odgovor.TipPoruke = Tip.OdgovorOnemoguciGlasovanje;

            lock (Posluzitelj.locker)
            {
                Posluzitelj.DozvoljenoGlasovanje = false;
            }

            return odgovor;
        }

        /// <summary>
        /// Metoda koja vraca podatke o rezultatima izbora.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka sa zahtjevom za rezultatima</param>
        /// <returns>Odlazna poruka s podacima o rezultatima</returns>
        private Poruka ObradiDohvatRezultata(JednostavnaPoruka pitanje)
        {
            PorukaListe odgovor = new PorukaListe();
            odgovor.TipPoruke = Tip.OdgovorRezultat;
            int odabranaJedinica = (int)pitanje.Podaci[0];

            using (BazingaEntities kontekst = new BazingaEntities())
            {
                var odabraneIzborneListe =
                     from iL in kontekst.izbornaLista
                     where iL.IDjedinica == odabranaJedinica
                     orderby iL.rbr
                     select iL;

                odgovor.PopisIzbornihLista = new List<IzbornaLista>();

                int i = 0;
                foreach (var lista  in odabraneIzborneListe)
                {

                    odgovor.PopisIzbornihLista.Add(
                       new IzbornaLista()
                       {
                           RedniBroj = (int)lista.rbr,
                           Naziv = lista.nazivlista,
                           BrojGlasova = (int)lista.brojglasova
                       });

                    i++;
                }
            }
            return odgovor;
        }
        
        
        

        #endregion

        #region Metode za obradu birackih poruka

        /// <summary>
        /// Vraca klijentu lozinku za odredjeno korisnicko ime.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka s korisnickim imenom.</param>
        /// <returns>Odlazna poruka s lozinkom</returns>
        private JednostavnaPoruka ObradiLozinkuBiraca(JednostavnaPoruka pitanje)
        {
            string OIB = (string)pitanje.Podaci[0];
            lock (Posluzitelj.locker)
            {
                // Provjeriti je li vec prijavljen birac s istim OIB-om, ako nije dodati ga medju prijavljene
                if (Posluzitelj.PrijavljeniBiraci.Contains(OIB))
                {
                    return
                        new JednostavnaPoruka(Tip.Pogreska, new object[] { "Birac s tim OIB-om prijavljen-" });
                }
                else
                {
                    Posluzitelj.PrijavljeniBiraci.Add(OIB);
                }

                using (BazingaEntities kontekst = new BazingaEntities())
                {
                    try
                    {
                        var odabraniBirac = (from b in kontekst.birac
                                             where b.OIB == OIB
                                             select b).Single();
                        // Ako birac nije vec glasovao poslati mu lozinku
                        if (odabraniBirac.glasovao != null && odabraniBirac.glasovao == 0)
                        {
                            return new JednostavnaPoruka()
                            {
                                TipPoruke = Tip.OdgovorLozinka,
                                Podaci = new object[] { odabraniBirac.lozinka }
                            };
                        }
                        else
                        {
                            return new JednostavnaPoruka
                            (Tip.Pogreska, new object[] { "Birac vec glasovao" });
                        }
                    }
                    catch (Exception)
                    {
                        return new JednostavnaPoruka
                        (Tip.Pogreska, new object[] { "Pogresan OIB." });
                    }
                }
            }
        }

        /// <summary>
        /// Metoda koja salje biracu odgovarajuce izborne liste ovisno o birackom mjestu.
        /// </summary>
        /// <param name="pitanje">Dolazna poruka s OIB-om</param>
        /// <returns>Odlazna poruka s izbornim listama</returns>
        private PorukaListe ObradiListeBiraca(JednostavnaPoruka pitanje)
        {
            PorukaListe odgovor = new PorukaListe();
            odgovor.TipPoruke = Tip.PitanjeListeBirac;
            string OIB = (string)pitanje.Podaci[0];

            using (BazingaEntities kontekst = new BazingaEntities())
            {
                var odabraniBirac = (from b in kontekst.birac
                                     where b.OIB == OIB
                                     select b).Single();

                var odabranaGrupaPrijava =
                     from iL in kontekst.izbornaLista
                     from pS in kontekst.prijavaStranke
                     from s in kontekst.stranka
                     where iL.IDjedinica == odabraniBirac.birackoMjesto.IDjedinica
                      && iL.IDjedinica == pS.IDjedinica
                      && iL.rbr == pS.rbr
                      && pS.IDstranka == s.IDstranka
                     group s by new { RedniBroj = iL.rbr, NazivListe = iL.nazivlista } into grupaPrijava
                     orderby grupaPrijava.Key.RedniBroj
                     select grupaPrijava;

                odgovor.PopisIzbornihLista = new List<IzbornaLista>();

                int i = 0;
                foreach (var prijave in odabranaGrupaPrijava)
                {
                    List<int> ListaIDStranaka = new List<int>();

                    foreach (var stranka in prijave)
                    {
                        ListaIDStranaka.Add((int)stranka.IDstranka);
                    }

                    odgovor.PopisIzbornihLista.Add(
                       new IzbornaLista()
                       {
                           RedniBroj = (int)prijave.Key.RedniBroj,
                           Naziv = prijave.Key.NazivListe,
                           PopisIDStranaka = ListaIDStranaka
                       });

                    i++;
                }
            }
            return odgovor;
        }

        /// <summary>
        /// Metoda koja biljezi odabir biraca
        /// </summary>
        /// <param name="pitanje">Dolazna poruka s OIB-om biraca i njegovim odabirom</param>
        /// <returns>Odlazna poruka o unosu</returns>
        private JednostavnaPoruka ObradiOdabirBiraca(JednostavnaPoruka pitanje)
        {
            string OIB = (string)pitanje.Podaci[0];
            int odabir = (int)pitanje.Podaci[1];

            using (BazingaEntities kontekst = new BazingaEntities())
            {
                var odabraniBirac = (from b in kontekst.birac
                                     where b.OIB == OIB
                                     select b).Single();
                var odabranaLista = (from iL in kontekst.izbornaLista
                                     where iL.IDjedinica == odabraniBirac.birackoMjesto.IDjedinica
                                         && iL.rbr == odabir
                                     select iL).Single();
                odabranaLista.brojglasova++;
                odabraniBirac.glasovao = 1;
                kontekst.SaveChanges();
            }

            return new JednostavnaPoruka() { TipPoruke = Tip.OdgovorOdabirBirac };
        }

        #endregion

    }
}